'''
author:cf
20180531:1.增加测试分析写入案例描述
20180611:
'''
from tkinter import Frame, Entry, Label, Button, StringVar, messagebox, filedialog
from mekk.xmind import XMindDocument
import os, xlrd, string
from collections import OrderedDict
from datetime import datetime, timedelta
from xlutils.copy import copy
from myXlsStyles import styleCommon
 
 
class xmind2xls():
   def __init__(self):
       self.frame = Frame(width=550, height=350)
       self.text = "xmind2xls"
       self.help = 'xmind2xls工具使用说明'
       self.var_xmind = StringVar()
       self.var_excel = StringVar()
       # 有序字典paths的key保存路径，value是一个list，保存备注内容和标签对应转化的数字
       self.paths = OrderedDict()
       # 中文标点，作为比对项，用来删除比对内容首尾的中文标点
       self.hanzi = r'，。、；‘’《》？：“”·~！￥…（）—【】'
       self.shuzi = r'1234567890./*-+'
       self.set_frame()
 
   def showHelp(self):
       textHelp = '''
       说明：
       1. python3实现，使用pyinstaller打包成exe文件。
       2. 确认exe同一个目录下有：ST离线模板.xls 。
       3. ST离线模板.xls文件的需求导入表sheet与案例导入表sheet的第4行可以修改。
          生成案例excel是复制的这两行。设计日期不填默认为当天时间。
       4. xmind最末尾节点有备注需要指定格式才能解析：
       (前置条件：XXX)步骤描述：YYY预期结果：ZZZ
          前置条件可以不写，前置条件与步骤描述直接的内容XXX作为前置条件，
          步骤描述与预期结果之间的内容YYY作为步骤描述，
          预期结果后的内容ZZZ作为预期结果。
       5. 最末尾节点有备注，包含测试分析 WWW 案例设计的，将中间内容 WWW 放入案例描述。
       6. xmind最末尾节点有标签，且标签是数字的，如2，会生成2行案例。
       7. xmind最末尾节点标签包含复用的，不生成需求案例。
       '''
       messagebox.showinfo(title='使用说明', message=textHelp)
 
   # 选择xmind方法，浏览button调用
   def selectXmind(self):
       path = filedialog.askopenfilename(initialdir=os.getcwd(),
                                         filetypes=[("Xmind文件", "*.xmind"), ("Xmind的mm文件", "*.mm")])
       self.var_xmind.set(path)
 
   # 选择excel方法，浏览button调用，不选默认当前目录下
   def selectExcel(self):
       xlsPath = filedialog.askopenfilename(initialdir=os.getcwd(), filetypes=[("EXCEL文件", "ST离线模板.xls")]).replace(
           '\\', '/')
       if xlsPath == '':
           xlsPath = str(os.getcwd() + '\ST离线模板.xls').replace('\\', '/')
       self.var_excel.set(xlsPath)
 
   # 获取父节点
   def getFatherTopic(self,path, topic):
       for pa in path[:-1].split('\\')[2:-1]:
           topicList = [val.get_title() for val in topic.get_subtopics()]
           topic = [val for val in topic.get_subtopics()][topicList.index(pa)]
       return topic
 
   # 读取xmind的节点，保存到paths的key中；保存备注内容和标签对应转化的数字到value中，value即temp=[]
   def findAllPaths(self,Topic, root, path='\\'):  # 递归找到所有末节点路径
       path = path + Topic.get_title() + '\\'
       # 如果Topic有子节点，递归读取，并保存节点对应的备注；没有子节点保存路径，备注，标签
       if len(list(Topic.get_subtopics())) != 0:
           for top in Topic.get_subtopics():  # 获取所有子节点
               self.findAllPaths(top, root, path)
       else:
           temp = []
           if Topic.get_note():
               temp.append(Topic.get_note())  # 获取备注内容
           else:
               temp.append(self.getFatherTopic(path, root).get_note())  # 获取父节点备注内容
           if Topic.get_label():
               try:
                   temp.append(int(Topic.get_label()))  # 获取标签内容，判断是否可以转int
               except Exception:
                   if Topic.get_label().find('复用') != -1:
                       temp.append(0)
                   else:
                       temp.append(1)
           else:
               temp.append(1)
           self.paths[path[:-1]] = temp
       return self.paths
 
   def mytry(self,wb, row, col, desrow, descol, src, des, sty):
       if len(des) == 1:
           try:
               temp = src.split(des[0])[1].strip('\n\r').strip(string.punctuation + self.hanzi). \
                   replace('\n\r', '\n').replace('\n\n', '\n')
               wb.write(row, col, temp, sty)
               return True
           except Exception:
               wb.write(desrow, descol, '', sty)
               return False
       elif len(des) == 2:
           try:
               temp = src.split(des[0])[1].split(des[1])[0].strip('\n\r').strip(
                   string.punctuation + self.hanzi).replace('\n\r', '\n').replace('\n\n', '\n')
               wb.write(row, col, temp, sty)
               return True
           except Exception:
               wb.write(desrow, descol, '', sty)
               return False
       else:
           pass
 
   def xmind2excel(self):
       try:
           excelFileName = self.var_excel.get()
           oldWb = xlrd.open_workbook(excelFileName, formatting_info=True)
       except Exception:
           messagebox.showerror(title='运行提示', message="%s文件不存在" % excelFileName)
           return
       xmindFileName = self.var_xmind.get()
       if xmindFileName == '':
           messagebox.showerror(title='报错', message='没有选择文件')
           return
       elif not xmindFileName.endswith('.xmind'):
           messagebox.showerror(title='报错', message='选择文件非xmind结尾')
           return
       try:
           w = XMindDocument.open(xmindFileName)  # 打开当前目录下的xmind文件
       except Exception:
           messagebox.showerror(title='报错', message='%s文件不存在' % xmindFileName)
           return
       root = w.get_first_sheet().get_root_topic()
 
       newWb = copy(oldWb)  # 通过copy函数把oldWb copy到newWb，然后通过编辑newWb来实现编辑已经存在的文件。
       newWs = newWb.get_sheet(1)  # 读取第二个sheet，即需求sheet
       row13 = oldWb.sheet_by_index(1).row_values(3)[:12]  # 第二个sheet第4行前12列的值
       newWt = newWb.get_sheet(2)  # 读取第三个sheet，即案例sheet
       row23 = oldWb.sheet_by_index(2).row_values(3)[:23]  # 第三个sheet第4行前23列的值
 
       today = datetime.strftime(datetime.now(), '%Y/%m/%d')  # 创建时间
       startrow = 3
       # 写需求sheet
       for key in self.findAllPaths(root, root).keys():
           if int(self.paths[key][1]) == 0:
               continue
           # 先复制模板内容，将第4行前12列的值复制到新的excel
           for st in range(len(row13)):
               newWs.write(startrow, st, row13[st], styleCommon)
           # 日期栏位为空特殊处理
           if row13[4] == '':
               newWs.write(startrow, 4, today, styleCommon)  # 日期
           else:
               detester = '1900/01/01'
               newWs.write(startrow, 4,
                           (datetime.strptime(detester, '%Y/%m/%d') + timedelta(days=int(row13[4]) - 2)).strftime(
                               '%Y/%m/%d'), styleCommon)
           keylist = key.split('\\')
           temp = ''
           for num in range(len(keylist) - 1):
               temp = temp + keylist[num] + '\\'
           newWs.write(startrow, 0, temp, styleCommon)  # 写入处理后的需求路径
           newWs.write(startrow, 1, keylist[-1], styleCommon)  # 写入需求名称
           newWs.write(startrow, 2, self.paths[key][0], styleCommon)  # 写入备注内容
           startrow = startrow + 1
 
       startrow = 3
       # 写案例sheet
       for key in self.findAllPaths(root, root).keys():
           # 按照标签数量复制行数，
           for times in range(int(self.paths[key][1])):
               # 先复制模板内容，将第4行前23列的值复制到新的excel
               for st in range(len(row23)):
                   newWt.write(startrow, st, row23[st], styleCommon)
               if row23[12] == '':
                   newWt.write(startrow, 12, today, styleCommon)  # 日期
               else:
                   detester = '1900/01/01'
                   newWt.write(startrow, 12,
                               (datetime.strptime(detester, '%Y/%m/%d') + timedelta(
                                   days=int(row23[12]) - 2)).strftime(
                                   '%Y/%m/%d'), styleCommon)
               # 写案例路径
               newWt.write(startrow, 0, key, styleCommon)
               temp = ''
               keylist = key.split('\\')
               for num in range(3, len(keylist)):
                   if num == len(keylist) - 1:
                       temp = temp + keylist[num]
                   else:
                       temp = temp + keylist[num] + '_'
               if times > 0:
                   temp = temp + str(times + 1)
               newWt.write(startrow, 2, temp, styleCommon)  # 写入处理好的案例名称，下划线'_'组装
               # 写案例描述
               try:
                   noteText = self.paths[key][0]
                   if noteText.find('测试分析') != -1:
                       try:
                           newWt.write(startrow, 3, noteText.split('测试分析')[1].split('案例设计')[0].strip('-'),
                                       styleCommon)
                       except Exception:
                           pass
               except Exception:
                   pass
               # 读取前置条件，步骤描述，预期结果，strip前后的换行符，中英文标点
               if not self.mytry(newWt, startrow, 4, startrow, 4, self.paths[key][0], ['前置条件', '步骤描述'], styleCommon):
                   self.mytry(newWt, startrow, 4, startrow, 4, self.paths[key][0], ['前置条件'], styleCommon)
 
               if not self.mytry(newWt, startrow, 5, startrow, 5, self.paths[key][0], ['步骤描述', '预期结果'], styleCommon):
                   self.mytry(newWt, startrow, 5, startrow, 6, self.paths[key][0], ['步骤描述'], styleCommon)
 
               self.mytry(newWt, startrow, 6, startrow, 6, self.paths[key][0], ['预期结果'], styleCommon)
 
               startrow = startrow + 1
       try:
           # savefilename = root.get_title() + '_' + datetime.strftime(datetime.now(), "%Y%m%d%H%M%S") + ".xls"
           savefilename = self.var_xmind.get()[:-6] + ".xls"
           newWb.save(savefilename)
           messagebox.showinfo(title='提示', message=savefilename + ' 文件已保存到对应目录')
       except Exception:
           messagebox.showerror(title='提示', message='没有选择保存文件名')
       finally:
           self.paths = OrderedDict()
 
   def set_frame(self):
       # 两个标签
       Label(self.frame, text='xmind文件:').place(x=30, y=90)
       Label(self.frame, text='模板 文件:').place(x=30, y=150)
       # 输入框 entry_xmind 和 entry_excel
       entry_xmind = Entry(self.frame, textvariable=self.var_xmind, width=43)
       entry_xmind.place(x=120, y=90)
       self.var_excel.set(str(os.getcwd() + '\ST离线模板.xls').replace('\\', '/'))
       entry_excel = Entry(self.frame, textvariable=self.var_excel, width=43)
       entry_excel.place(x=120, y=150)
       # 两个button
       Button(self.frame, text='浏览', command=self.selectXmind, height=1).place(x=490, y=85)
       Button(self.frame, text='浏览', command=self.selectExcel, height=1).place(x=490, y=145)
       Button(self.frame, text='生成excel案例', command=self.xmind2excel).place(x=230, y=200)